package gui.beans;

import gui.eventos.TaskActionEvent;
import gui.eventos.TaskActionListener;
import gui.iconos.Icono;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import javax.swing.Icon;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import datos.Incidencia;
import datos.Proyecto;
import datos.Tarea;

@SuppressWarnings("serial")
public class TaskTree extends JTree {

	private TaskTreeModel modelo = null;
	
	private Vector<TaskActionListener> listeners = null;
	
	private JMenuItem jMINueva = null;
	private JMenuItem jMINuevoProyecto = null;
	private JMenuItem jMIEliminar = null;
	private JMenuItem jMIInforme = null;
	private JMenu jMCambiarEstado = null;

	public TaskTree(List<Tarea> tareas) {
		super(new TaskTreeModel(tareas));
		modelo = (TaskTreeModel)getModel();
		listeners = new Vector<TaskActionListener>();
		setCellRenderer(new IncidenciaTreeRenderer());
		addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				TreePath selPath = getPathForLocation(e.getX(), e.getY());
				setSelectionPath(selPath);
				//if (e.isPopupTrigger()) {
				if(e.getButton() == 3) {
					if (selPath != null)
						if (!(selPath.getLastPathComponent() instanceof String))
							getPopupMenu().show(e.getComponent(), e.getX(), e.getY());
						else
							getNoIncPopupMenu().show(e.getComponent(), e.getX(), e.getY());
				} else {
					if (e.getClickCount() == 2) {
						if(getLastSelectedPathComponent() instanceof Incidencia)
							fireTaskAction(new TaskActionEvent(this, TaskActionEvent.TAREA_SELECCIONADA, (Incidencia)getLastSelectedPathComponent()));
						if(getLastSelectedPathComponent() instanceof Proyecto)
							fireTaskAction(new TaskActionEvent(this, TaskActionEvent.TAREA_SELECCIONADA, (Proyecto)getLastSelectedPathComponent()));
						
					}
				}
			}
		});
	}

	public Tarea cargarLista(List<Tarea> tareas) {
		modelo.setListaIncidencias(tareas);
		this.updateUI();
		return null;
	}
	
	public void addIncidenciaActionListener(TaskActionListener l){
		listeners.add(l);
	}
	
	private void fireTaskAction(TaskActionEvent e){
		Enumeration<TaskActionListener> listenerCount = listeners.elements();
		while (listenerCount.hasMoreElements()) {
			TaskActionListener listener = (TaskActionListener) listenerCount.nextElement();
			listener.actionPerformed(e);
		}
	}
	
	public void addNewActionListener(ActionListener listener){
		getJMINueva().addActionListener(listener);
	}
	
	public void addDeleteActionListener(ActionListener listener){
		getJMIEliminar().addActionListener(listener);
	}
	
	public void addReportActionListener(ActionListener listener){
		getJMIInforme().addActionListener(listener);
	}

	private JPopupMenu getPopupMenu() {
		JPopupMenu jpm = new JPopupMenu();
		jpm.add(getMenuCrear());
		jpm.add(getJMCambiarEstado());
		jpm.add(getJMIEliminar());
		jpm.addSeparator();
		jpm.add(getJMIInforme());
		return jpm;
	}

	private JPopupMenu getNoIncPopupMenu() {
		JPopupMenu jpm = new JPopupMenu();
		jpm.add(getMenuCrear());
		return jpm;
	}
	
	private JMenu getMenuCrear(){
		JMenu menu = new JMenu("Crear");
		menu.add(getJMINueva());
		menu.add(getJMINuevoProyecto());
		return menu;
	}

	/**
	 * This method initializes jMINueva
	 * 
	 * @return javax.swing.JMenuItem
	 */
	private JMenuItem getJMINueva() {
		if (jMINueva == null) {
			jMINueva = new JMenuItem();
			jMINueva.setIcon(Icono.getIcono("incidencia.png"));
			jMINueva.setText("Incidencia");
			jMINueva.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e){
					String estado = null;
					if(getLastSelectedPathComponent() instanceof String){
						estado = (String)getLastSelectedPathComponent();
					} else {
						estado = (String)getSelectionPath().getPathComponent(getSelectionPath().getPathCount() -2);
					}
					fireTaskAction(new TaskActionEvent(this, TaskActionEvent.NUEVA_INCIDENCIA, estado));
				}
			});
		}
		return jMINueva;
	}
	
	/**
	 * This method initializes jMINueva
	 * 
	 * @return javax.swing.JMenuItem
	 */
	private JMenuItem getJMINuevoProyecto() {
		if (jMINuevoProyecto == null) {
			jMINuevoProyecto = new JMenuItem();
			jMINuevoProyecto.setIcon(Icono.getIcono("proyecto.png"));
			jMINuevoProyecto.setText("Proyecto");
			jMINuevoProyecto.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e){
					String estado = null;
					if(getLastSelectedPathComponent() instanceof String){
						estado = (String)getLastSelectedPathComponent();
					} else {
						estado = (String)getSelectionPath().getPathComponent(getSelectionPath().getPathCount() -2);
					}
					fireTaskAction(new TaskActionEvent(this, TaskActionEvent.NUEVO_PROYECTO, estado));
				}
			});
		}
		return jMINuevoProyecto;
	}
	
	/**
	 * This method initializes jMICambiarEstado
	 * 
	 * @return javax.swing.JMenuItem
	 */
	private JMenu getJMCambiarEstado() {
		if (jMCambiarEstado == null) {
			jMCambiarEstado = new JMenu();
			jMCambiarEstado.setText("Cambiar estado");
			String [] estados = Tarea.ESTADOS;
			for(int i=0; i<estados.length;i++)
				jMCambiarEstado.add(crearItemCambioEstado(estados[i]));
		}
		return jMCambiarEstado;
	}
	
	private JMenuItem crearItemCambioEstado(final String estado){
		JMenuItem item = new JMenuItem();
		item.setText(estado);
		item.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				fireTaskAction(new TaskActionEvent(this, TaskActionEvent.CAMBIAR_ESTADO, (Tarea)getLastSelectedPathComponent(), estado));
			}
		});
		return item;
	}

	/**
	 * This method initializes jMIEliminar
	 * 
	 * @return javax.swing.JMenuItem
	 */
	private JMenuItem getJMIEliminar() {
		if (jMIEliminar == null) {
			jMIEliminar = new JMenuItem();
			jMIEliminar.setIcon(Icono.getIcono("eliminar.png"));
			jMIEliminar.setText("Eliminar");
			jMIEliminar.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e){
					fireTaskAction(new TaskActionEvent(this, TaskActionEvent.ELIMINAR_INCIDENCIA, (Tarea)getLastSelectedPathComponent()));
				}
			});
		}
		return jMIEliminar;
	}

	/**
	 * This method initializes jMIInforme
	 * 
	 * @return javax.swing.JMenuItem
	 */
	private JMenuItem getJMIInforme() {
		if (jMIInforme == null) {
			jMIInforme = new JMenuItem();
			jMIInforme.setIcon(Icono.getIcono("informe.png"));
			jMIInforme.setText("Generar informe");
			jMIInforme.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e){
					fireTaskAction(new TaskActionEvent(this, TaskActionEvent.GENERAR_INFORME, (Tarea)getLastSelectedPathComponent()));
				}
			});
		}
		return jMIInforme;
	}
}

class TaskTreeModel implements TreeModel {
	
	private List<Tarea> tareas = null;
	private final String root = "Tareas"; // The root identifier
	private final String[] estados = Tarea.ESTADOSTREE;

	private Vector<TreeModelListener> listeners; // Declare the listeners vector

	public TaskTreeModel(List<Tarea> tareas) {
		this.tareas = tareas;
		listeners = new Vector<TreeModelListener>();
	}

	public void setListaIncidencias(List<Tarea> tareas) {
		this.tareas = tareas;
	}

	public Object getRoot() {
		return root;
	}

	public Object getChild(Object parent, int index) {
		String padre = (String) parent;
		if (padre.equals(root))
			return estados[index];

		// Estamos en un estado
		int cont = 0;
		Iterator<Tarea> i = tareas.iterator();
		while (i.hasNext()) {
			Tarea tarea = i.next();
			if (tarea.getEstado().equals(padre)) {
				if (index == cont)
					return tarea;
				else
					cont++;
			}
		}
		return null;
	}

	public int getChildCount(Object parent) {
		String padre = (String) parent;
		if (padre.equals(root)){
			if(hayTareasSinEstado())
				return estados.length;
			return estados.length -1;
		}

		// Estamos en un estado
		int cont = 0;
		Iterator<Tarea> i = tareas.iterator();
		while (i.hasNext()) {
			Tarea tarea = i.next();
			if (tarea.getEstado().equals(padre)) {
				cont++;
			}
		}
		return cont;
	}

	public int getIndexOfChild(Object parent, Object child) {
		String padre = (String) parent;
		if (padre.equals(root))
			for (int x = 0; x < estados.length; x++) {
				if (estados[x].equals(child))
					return x;
			}

		// Estamos en un estado
		int cont = 0;
		Iterator<Tarea> i = tareas.iterator();
		while (i.hasNext()) {
			Tarea tarea = i.next();
			if (tarea.getEstado().equals(padre)) {
				if (child == tarea)
					return cont;
				else
					cont++;
			}
		}
		return 0;
	}

	public boolean isLeaf(Object node) {
		return (node instanceof Incidencia) || (node instanceof Proyecto);
	}

	public void addTreeModelListener(TreeModelListener l) {
		if (l != null && !listeners.contains(l)) {
			listeners.addElement(l);
		}
	}

	public void removeTreeModelListener(TreeModelListener l) {
		if (l != null) {
			listeners.removeElement(l);
		}
	}

	public void valueForPathChanged(TreePath path, Object newValue) {
		// Does Nothing!
	}

	public void fireTreeNodesInserted(TreeModelEvent e) {
		Enumeration<TreeModelListener> listenerCount = listeners.elements();
		while (listenerCount.hasMoreElements()) {
			TreeModelListener listener = (TreeModelListener) listenerCount.nextElement();
			listener.treeNodesInserted(e);
		}
	}

	public void fireTreeNodesRemoved(TreeModelEvent e) {
		Enumeration<TreeModelListener> listenerCount = listeners.elements();
		while (listenerCount.hasMoreElements()) {
			TreeModelListener listener = (TreeModelListener) listenerCount.nextElement();
			listener.treeNodesRemoved(e);
		}

	}

	public void fireTreeNodesChanged(TreeModelEvent e) {
		Enumeration<TreeModelListener> listenerCount = listeners.elements();
		while (listenerCount.hasMoreElements()) {
			TreeModelListener listener = (TreeModelListener) listenerCount.nextElement();
			listener.treeNodesChanged(e);
		}

	}

	public void fireTreeStructureChanged(TreeModelEvent e) {
		Enumeration<TreeModelListener> listenerCount = listeners.elements();
		while (listenerCount.hasMoreElements()) {
			TreeModelListener listener = (TreeModelListener) listenerCount.nextElement();
			listener.treeStructureChanged(e);
		}
	}
	
	private boolean hayTareasSinEstado(){
		Iterator<Tarea> i = tareas.iterator();
		while(i.hasNext()){
			Tarea tarea = i.next();
			if(tarea.getEstado().equals(""))
				return true;
		}
		return false;
	}
}

@SuppressWarnings("serial")
class IncidenciaTreeRenderer extends DefaultTreeCellRenderer {

	public IncidenciaTreeRenderer() {
	}

	public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {

		super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
				
		if (value instanceof String) {
			String s = (String) value;
			if (s.equals(""))
				setText("Sin estado");
			
		}
		if(value instanceof Incidencia){
			Icon icono = Icono.getIcono("incidencia.png");
			if(icono != null)
				setIcon(icono);
		}
		
		if(value instanceof Proyecto){
			Icon icono = Icono.getIcono("proyecto.png");
			if(icono != null)
				setIcon(icono);
		}
		return this;
	}
}
